#include "vtor_flash_eeprom.h"

#ifdef __VTOR_FLASH_EEPROM__

// 加入用户工程宏
#ifdef __USER_PROJECT_DEMO__

#include "main.h"
#include "vtor_printf.h"


// #define FLASH_PAGE_SIZE		0x400U
#define VtorFlashDemoPageSize	FLASH_PAGE_SIZE

VtorFlashEeprom demoEeprom = 
{
	.flashStartAddress = 0x0801e000,
	.flashPageSize = 0x0400,
	.flashPageCnt = 4,
	.eepromSize = 0x0100,
};

VtorFlashLogger demoLogger = 
{
	.flashStartAddress = 0x0801f000,
	.flashPageSize = 0x0400,
	.flashPageCnt = 4,
};

uint32_t VtorFlash_Lock(void)
{
	return HAL_FLASH_Lock();
}

uint32_t VtorFlash_Unlock(void)
{
	return HAL_FLASH_Unlock();
}

uint32_t VtorFlash_Write32(uint32_t addr, uint32_t value)
{
	return HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, value);
}

uint32_t VtorFlash_Write64(uint32_t addr, uint64_t value)
{
	return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, value);
}


uint32_t VtorFlash_Erase(uint32_t addr, int32_t pageCnt)
{
	uint32_t error = 0;
	FLASH_EraseInitTypeDef eraseStruct;
	eraseStruct.TypeErase = FLASH_TYPEERASE_PAGES;
	eraseStruct.Banks = 0;
	eraseStruct.PageAddress = addr;
	eraseStruct.NbPages = pageCnt;
	HAL_FLASH_Unlock();
	HAL_FLASHEx_Erase(&eraseStruct, &error);
	HAL_FLASH_Lock();
	return error;
}

// 如果这段区域全是0xff，返回1，表示可以直接写
//            存在非0xff，返回0，表示必须擦除后才能写
uint8_t VtorFlash_CheckAll0xff(uint32_t addr, uint32_t len)
{
	uint32_t* flashData = (uint32_t*)addr;
	for(int i = 0; i < len / 4; i++)
	{
		// 如果不是全f，返回0，，后续看情况进行擦除
		if(0xffffffff != flashData[i])
		{
			return 0;
		}
	}
	return 1;
}



uint32_t VtorFlash_Write(uint32_t addr, uint32_t* data, uint32_t len)
{
	if(0 == addr || 0 == len)
	{
		return 0;
	}
	if(addr & 0x03 || len & 0x03)
	{
		return 0;
	}
	if((uint32_t)data & 0x03 || (uint32_t)data & 0x03)
	{
		return 0;
	}
	uint32_t flashAddr = addr;
	uint32_t* memData = (uint32_t*)data;
	HAL_FLASH_Unlock();
	for(uint32_t i = 0; i< len / 4; i++)
	{
		HAL_StatusTypeDef flashRet =
			HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flashAddr + i * 4, memData[i]);
		// 如果出错，直接返回
		if(HAL_OK != flashRet)
		{
			HAL_FLASH_Lock();
			// 外面使用0判断写失败，不传输具体错误原因
			return 0;
		}
	}
	HAL_FLASH_Lock();
	return addr;
}


uint32_t VtorFlash_Read(uint32_t addr, uint32_t* data, uint32_t len)
{
	if(0 == addr || 0 == len)
	{
		return 0;
	}
	if(addr & 0x03 || len & 0x03)
	{
		return 0;
	}
	uint32_t* flashData = (uint32_t*)addr;
	for(uint32_t i = 0; i < len/4; i++)
	{
		data[i] = flashData[i];
	}
	return addr;
}


uint32_t VtorFlash_overWriteBuf[VtorFlashDemoPageSize/4];
uint32_t VtorFlash_OverWrite(uint32_t addr, uint32_t* data, uint32_t len)
{
	uint32_t writeRet = addr;
	while(len)
	{
		// 计算 页内开始覆盖写地址    页起始地址   页剩余空间
		uint32_t pageOverWriteAddr = addr % VtorFlashDemoPageSize;
		uint32_t pageStartAddr = addr - pageOverWriteAddr;
		uint32_t pageRemain = VtorFlashDemoPageSize - pageOverWriteAddr;
		
		// 页剩余大小 总长度 选较小值，将数据读出来
		uint32_t curWriteLen = pageRemain < len ? pageRemain : len;
		
		// 如果全f，返回1，直接写即可
		int all0xffFlag = VtorFlash_CheckAll0xff(addr, curWriteLen);
		if(all0xffFlag)
		{
			writeRet = VtorFlash_Write(addr, data, curWriteLen);
		}
		else
		{
			VtorFlash_Read(pageStartAddr,
				VtorFlash_overWriteBuf, VtorFlashDemoPageSize);
			for(int index = 0; index < curWriteLen / 4; index++)
			{
				VtorFlash_overWriteBuf[pageOverWriteAddr/4 + index] = data[index];
			}
			writeRet = VtorFlash_Erase(pageStartAddr, 1);
			writeRet = VtorFlash_Write(pageStartAddr,
				VtorFlash_overWriteBuf, VtorFlashDemoPageSize);
		}
		if(0 == writeRet)
		{
			addr = 0;
			break;
		}
		data += curWriteLen / 4;
		addr += curWriteLen;
		len -= curWriteLen;
	}
	// 如果发生了错误，返回0
	return addr;
}



#endif // __USER_PROJECT__

#endif // __VTOR_FLASH_EEPROM__

